package com.rengwuxian.coursecoroutines._1_basics

import android.os.Bundle
import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import android.widget.TextView
import androidx.activity.ComponentActivity
import androidx.lifecycle.lifecycleScope
import com.rengwuxian.coursecoroutines.R
import com.rengwuxian.coursecoroutines.common.Contributor
import com.rengwuxian.coursecoroutines.common.gitHub
import kotlinx.coroutines.launch
import kotlin.concurrent.thread

/**
 * 消除魔法：挂起函数为什么不卡线程？
 * 线程切换、主线程、线程和协程
 *
 * 传统java程序，无法做到从子线程切到主线程，无法把一个线程从中途撕开，把代码塞进去。服务器程序不需要线程一直循环。且从底层代码中没有Main线程的概念。
 *
 * 而android可以，是因为主线程是一个无限循环的，用不结束的，会一直从任务队列中取任务来执行。切到主线程，是通过handler.post方式。
 * 这种也不是从主线程塞入代码，而是主线程主动来取任务。
 * 可以通过Executors.newCachedThreadPool().execute() 扔到线程池中执行。
 *
 * 比如：HandlerThread 开启子线程，子线程会一直循环，从任务队列中取任务来执行。
 *
 * 协程的线程切换：
 * 挂起函数是切到线程池来执行（Default\IO）
 * 通过Main来切回来，也是通过handler.post方式（Android平台提供的机制）。
 * 原理也是回调的形式，kotlin对编译过程进行干预，在挂起函数前后，拆分，组装成嵌套回调。
 * 比如：伪代码（实际比这个复杂的多）
 * lifecycleScope.launch {
 * //      switchToBackground {
 * //        gitHub.contributors("square", "retrofit")
 * //        switchToMain {
 * //          showContributors(contributors)
 * //        }
 * //      }
 *     }
 * 协程并没有等待，而是回调，然后抛到主线程的任务队列中，和传统线程写法一样。
 *
 * 协程有自己的状态机机制，挂起和恢复是其中一环。
 */
class DeMagicActivity : ComponentActivity() {
  private lateinit var infoTextView: TextView

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.layout_1)
    infoTextView = findViewById(R.id.infoTextView)

    lifecycleScope.launch {
//      switchToBackground {
//        gitHub.contributors("square", "retrofit")
//        switchToMain {
//          showContributors(contributors)
//        }
//      }
    }
  }

  private fun coroutinesStyle() = lifecycleScope.launch {
    val contributors = gitHub.contributors("square", "retrofit")
    showContributors(contributors)
  }

  private fun showContributors(contributors: List<Contributor>) = contributors
    .map { "${it.login} (${it.contributions})" }
    .reduce { acc, s -> "$acc\n$s" }
    .let { infoTextView.text = it }
}